package edu.server.dominio;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

import edu.server.repositorio.ElementoProducto;
import edu.server.repositorio.MaterialProducto;
import edu.server.repositorio.MedidaFijaProducto;
import edu.server.repositorio.Producto;
import edu.server.util.HibernateUtil;

public class D_Producto {

	public D_Producto(){
		
	}
	
	/**
	 * Método que busca en la base de datos toda la información de los productos.
	 * @return una lista de productos.
	 */
	@SuppressWarnings("unchecked")
	public List<Producto> buscarProductos(){
		
		List<Producto> productos;
		
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		
		session.beginTransaction();
		
		String hql = "FROM Producto";
		
		Query query = session.createQuery(hql);
		
		productos = query.list();
		
		for(Producto producto : productos){
			Hibernate.initialize(producto.getElementoProducto());
			Hibernate.initialize(producto.getElementoProducto().getClaseProducto());
			Hibernate.initialize(producto.getMaterialProducto());
			Hibernate.initialize(producto.getMedidaFijaProducto());
			Hibernate.initialize(producto.getMedidasVariablesEstandars());
		}
			
		session.close();
		
		return productos;
	}
	
	
	/**
	 * Método que registra en la base de datos un producto.
	 * @param producto. Producto a guardar en la base de datos.
	 */
	public void registrarProducto(Producto producto) throws Exception
	{		
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		
		try{
			session.beginTransaction();
	
			//guardamos la clase del producto
			session.saveOrUpdate(producto.getElementoProducto().getClaseProducto());
			
			//seteamos el id de la clase de producto recientemente guardada al elemento del producto
			producto.getElementoProducto().getId().setCodigoClaseProducto(producto.getElementoProducto().getClaseProducto().getCodigoClaseProducto());
			
			//guardamos el elemento del producto
			session.saveOrUpdate(producto.getElementoProducto());
			
			//guardamos el material del producto
			session.saveOrUpdate(producto.getMaterialProducto());
			
			//guardamos la medida fija del producto
			session.saveOrUpdate(producto.getMedidaFijaProducto());
			
			//guardamos el producto
			session.saveOrUpdate(producto);
			
			session.getTransaction().commit();
		}
		
		catch(Exception e)
		{
			session.getTransaction().rollback();
			throw e;
		}
	}
	
	
	/**
	 * Método que busca en la base de datos el producto que cumple con los parámentros pasados
	 * @param elemento. Elemento de producto.
	 * @param material. Material de producto.
	 * @param medidaFija. Medida fija de producto.
	 * @return Producto. Retorna el producto que tiene los datos pasado como parámetro.
	 */
	public Producto buscarProducto(ElementoProducto elemento, MaterialProducto material, MedidaFijaProducto medidaFija)
	{
		Producto producto;
		
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		
		session.beginTransaction();
		
		Criteria criteria = session.createCriteria(Producto.class);
	
		criteria.add(Restrictions.eq("elementoProducto", elemento));
		criteria.add(Restrictions.eq("materialProducto", material));
		criteria.add(Restrictions.eq("medidaFijaProducto", medidaFija));
		
		producto = (Producto) criteria.uniqueResult();
	
 		session.close();
		
		return producto;
	}
	
	
	/**
	 * Método que busca en la base de datos los productos que tienen la clase, el elemento y/o material que se pasan como parámetro.
	 * @param codigoClase. Clase del producto a filtrar. Un valor cero indica que no se debe filtrar por clase.
	 * @param codigoElemento. Elemento del producto a filtrar. Un valor cero indica que no se debe filtrar por elemento.
	 * @param codigoMaterial. Material del producto a filtrar. Un valor cero indica que no se debe filtrar por material.
	 * @return List<Producto>. Retorna una lista de productos que matchean con los parámetros pasados..
	 */
	@SuppressWarnings("unchecked")
	public List<Producto> buscarProductos(int codigoClase, int codigoElemento, int codigoMaterial)
	{
		List<Producto> productos;
		
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		
		session.beginTransaction();
		
		//dependiendo de los valores que se nos pasan como parámentro realizamos el filtro correspondiente.
		
		//no se aplican filtros
		if(codigoClase == 0 && codigoElemento == 0 && codigoMaterial == 0)
			productos = session.createQuery("FROM Producto").list();
		
		else if(codigoElemento == 0)
			//se filtra por clase
			if(codigoMaterial == 0)
				productos = session.createQuery("FROM Producto P WHERE P.elementoProducto.id.codigoClaseProducto = " + codigoClase).list();
		
			//se filtra por material
			else if(codigoClase == 0)
				productos = session.createQuery("FROM Producto P WHERE P.materialProducto.codigoMaterialProducto = " + codigoMaterial).list();
		
			//se filtra por clase y material
			else
				productos = session.createQuery("FROM Producto P WHERE P.elementoProducto.id.codigoClaseProducto = " + codigoClase +
												" AND P.materialProducto.codigoMaterialProducto = " + codigoMaterial).list();
	
		else
			//se filtra por clase y elemento
			if(codigoMaterial == 0)
				productos = session.createQuery("FROM Producto P WHERE P.elementoProducto.id.codigoClaseProducto = " + codigoClase +
												" AND P.elementoProducto.id.codigoElementoProducto = " + codigoElemento).list();
			
			//si filtra por clase, elemento y material
			else
				productos = session.createQuery("FROM Producto P WHERE P.elementoProducto.id.codigoClaseProducto = " + codigoClase +
												" AND P.elementoProducto.id.codigoElementoProducto = " + codigoElemento +
												" AND P.materialProducto.codigoMaterialProducto = " + codigoMaterial).list();
				
 		
		//inicializamos los datos del producto
		for(Producto producto : productos){
			Hibernate.initialize(producto.getElementoProducto());
			Hibernate.initialize(producto.getElementoProducto().getClaseProducto());
			Hibernate.initialize(producto.getMaterialProducto());
			Hibernate.initialize(producto.getMedidaFijaProducto());
			Hibernate.initialize(producto.getMedidasVariablesEstandars());
		}
		
		session.close();
		
		return productos;
	}
	
	
	/**
	 * Método que busca en la base de datos el producto que tiene el id pasado como parámetro.
	 * @param id. Id del producto que se pretende buscar.
	 * @return Producto. Retorna el producto que tiene el id pasado como parámetro.
	 */
	public Producto buscarProducto(int id)
	{
		Producto producto;
		
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		
		session.beginTransaction();
		
		producto = (Producto) session.get(Producto.class, id);
		
		Hibernate.initialize(producto.getElementoProducto());
		Hibernate.initialize(producto.getElementoProducto().getClaseProducto());
		Hibernate.initialize(producto.getMaterialProducto());
		Hibernate.initialize(producto.getMedidaFijaProducto());
		Hibernate.initialize(producto.getMedidasVariablesEstandars());
		
		session.close();
		
		return producto;
	}
	
	
	/**
	 * Método que busca en la base de datos el producto que tiene el id pasado como parámetro.
	 * @param id. Id del producto que se pretende buscar.
	 * @return Producto. Retorna el producto que tiene el id pasado como parámetro.
	 */
	public Producto buscarProductoCompleto(int id)
	{
		Producto producto;
		
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		
		session.beginTransaction();
		
		producto = (Producto) session.get(Producto.class, id);
		
		if(producto != null)
		{
			Hibernate.initialize(producto.getElementoProducto());
			Hibernate.initialize(producto.getElementoProducto().getClaseProducto());
			Hibernate.initialize(producto.getMaterialProducto());
			Hibernate.initialize(producto.getMedidaFijaProducto());
			Hibernate.initialize(producto.getMedidasVariablesEstandars());
		}
		
		session.close();
		
		return producto;
	}
}
